use crate::{
    helpers::{count_ttr, create_ttr, link_finder, remove_tracking_parameters, wrap_url, Bot, redirect_frontends},
    keyboards,
    // models::{Post, User, UserPost},
};
use anyhow::{Context, Result};
use db::{Db, models::Post};
 use tokio_stream::StreamExt;
use log::info;

use serde::{Deserialize, Serialize};
use std::{convert::TryInto, sync::Arc, ops::Deref};
use std::str::FromStr;
use teloxide::{
    prelude::*,
    types::{UserId},
    utils::markdown::{escape, escape_link_url},
};
use tokio::sync::Mutex;
/// Add new url to the db and belong it to user
pub async fn add(bot: Bot, m: Message, db: Db) -> Result<()> {
    let urls = link_finder(&m);
    if urls.is_empty() {
        info!("No urls in the message!");
    }
    // let bot = Arc::new(Mutex::new(bot));
    info!("Urls in the message: {:#?}", urls);
    let telegram_user = m.from().context("Error while get telegram user data:")?;
    let telegram_user_id = telegram_user.id;
    let user_username = telegram_user.username.clone();
    // let user_id = db::models::MatrixOrTelegramId::TelegramId{id: telegram_user_id, username: user_username};
    let user = db.get_user_id_tg(&telegram_user_id).await?;
    let mut urls = tokio_stream::iter(urls);
    // for mut url in urls {
        while let Some(mut url) = urls.next().await {
    let db = db.clone();
    let bot = bot.clone();
           let task:tokio::task::JoinHandle<Result<()>> = tokio::spawn(async move {
            println!("test");
        remove_tracking_parameters(&mut url);
        let mut real_url = real_url(&url).await;
        remove_tracking_parameters(&mut real_url);
        // If post exists, see if it belongs to the user.
    let post = {
let real_url_str = real_url.as_str();
    match db.find_post(real_url_str).await.context("cannot find post")? {
        Some(post) => post, 
        None => {
            let post = create_post(real_url).await?;
            db.create_post(&post).await.context("cannot create post")?
        }
    }
    };
    let user_post = {
        match db.find_user_post(user, post.id()).await.context("cannot find user post")? {
            Some(user_post) => user_post,
            None => {
                db.create_user_post(post.id(), url.as_str(), user).await.context("cannot create user post")?
            }
        }
    };
            let mut answer = {
                let url_str = url.as_str();
                if let Some(title) = post.title() {
                    wrap_url(url_str, &title)
                } else {
                    escape(&escape_link_url(url_str))
                }
            };
            // let ttr = count_ttr(post.word_count());
            if let Some(ttr) = post.word_count() {
                create_ttr(&mut answer, ttr.try_into().unwrap())
            };
                bot
                // .lock()
                // .await
                // .deref()
                .send_message(telegram_user_id, answer)
                    .reply_markup(keyboards::standart_keyboard(
                        &user_post.id().hyphenated().to_string(),
                        user_post.read(),
                        user_post.favorite(),
                    ))
                    .await?;
        // if let Ok(post_id) = post_exists(&real_url, &db).await {
        //     if let Some(user_post_info) =
        //         check_duplicates_in_post_map(user_id, post_id, &db).await?
        //     {
        //         bot.send_message(telegram_user.id, url.to_string())
        //             .reply_markup(keyboards::standart_keyboard(
        //                 &post_id.hyphenated().to_string(),
        //                 user_post_info.read,
        //                 user_post_info.favorite,
        //             ))
        //             .await?;
        //     }
        //     // If post does not exist, create it
        // } else {
        //     let post = create_post(real_url).await?;
        //     save_post_to_db(&post, &db).await?;
        //     append_post_to_user(user_id, post.id(), &db, &url).await?;
        //     let _post_id = post.id();

        //     log::info!("Successful saved post");
        //     let mut answer = {
        //         let url_str = url.as_str();
        //         if let Some(title) = post.title() {
        //             wrap_url(url_str, &title)
        //         } else {
        //             escape(&escape_link_url(url_str))
        //         }
        //     };
        //     let ttr = count_ttr(post.word_count);
        //     if let Some(ttr) = ttr {
        //         create_ttr(&mut answer, ttr)
        //     };
        //     bot.send_message(telegram_user.id, answer)
        //         .reply_markup(keyboards::standart_keyboard(
        //             &post.id().hyphenated().to_string(),
        //             false,
        //             false,
        //         ))
        //         //   .parse_mode(ParseMode::MarkdownV2)
        //         .await?;
    
        Ok(())
        // }
        });
        task.await??;
    }


    Ok(())
}
use url::Url;
// Open web page using reqwest and get final url
async fn real_url(original_url: &Url) -> Url {
    match reqwest::get(original_url.to_owned()).await {
        Err(e) => {
            info!("{:#?}", e);
            original_url.to_owned()
        }
        Ok(res) => {
            //TODO: work with url
            let real_url = res.url().to_owned();
            info!("{}", real_url);
            real_url
        }
    }
}
use time::OffsetDateTime;
use uuid::Uuid;
fn created() -> OffsetDateTime {
    OffsetDateTime::now_utc()
}

pub async fn create_post(real_url: Url) -> Result<Post> {
    let created = created();
    let id = uuid::Uuid::new_v4();
    let mut title = None;
    let mut word_count = None;
    let alternative_url = redirect_frontends(&real_url).map(|s| s.to_string());
    //let MercuryReturn { title, word_count } = parse(&real_url).context("NoneError")?;
    match parser::parse(&real_url).await {
        Ok(output) => {
            title = output.title;
            word_count = output.duration;
        }
        Err(e) => {
            info!("mercury error! {:#?}", e);
        }
    };
      let post = Post::new(
        id,
        title,
        word_count.map(|s| s.seconds() as i64),
        real_url.to_string(),
        alternative_url,
        created,
      ); 
    // let post = Post::builder()
    //     .id(id)
    //     .title(title)
    //     .word_count(word_count.map(|s|s.seconds() as i64))
    //     .real_url(real_url.to_string())
    //     .created(created)
    //     .alternative_url(alternative_url)
    //     .build();
    Ok(post)
}